package com.jhws.core.push;

import com.jhws.util.LogHelper;
import com.turo.pushy.apns.ApnsClient;
import com.turo.pushy.apns.ApnsClientBuilder;
import com.turo.pushy.apns.PushNotificationResponse;
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
import com.turo.pushy.apns.util.TokenUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.springframework.stereotype.Service;
import sun.rmi.runtime.Log;

import java.io.File;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class IosApnsPushy {
    private ApnsClient apnsClientDev;
    private ApnsClient apnsClientProd;
    private static final Semaphore semaphore = new Semaphore(10000);

    public IosApnsPushy(String name,String password) throws Exception{

        apnsClientDev = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
                .setClientCredentials(new File(this.getClass().getResource("/").toString().substring(5)+name+".p12"), password)
                .build();

        apnsClientProd = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
                .setClientCredentials(new File(this.getClass().getResource("/").toString().substring(5)+name+".p12"), password)
                .build();
    }

    public void push(final List<String> deviceTokens, String alertTitle, String alertBody, Map<String,String> custom,boolean isProd) {
        ApnsClient apnsClient = null;
        long total = deviceTokens.size();

        final CountDownLatch latch = new CountDownLatch(deviceTokens.size());

        final AtomicLong successCnt = new AtomicLong(0);

        for (String deviceToken : deviceTokens) {
            ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
            payloadBuilder.setAlertBody(alertBody);
            payloadBuilder.setAlertTitle(alertTitle);

            for (Map.Entry<String, String> entry : custom.entrySet()) {
                payloadBuilder.addCustomProperty(entry.getKey(),entry.getValue());
            }

            String payload = payloadBuilder.buildWithDefaultMaximumLength();
            final String token = TokenUtil.sanitizeTokenString(deviceToken);
            SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, "com.jhws.wst.voip", payload);

            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                LogHelper.i("ios push get semaphore failed, deviceToken:"+ deviceToken);
                e.printStackTrace();
            }

            if(isProd)
                apnsClient = apnsClientProd;
            else
                apnsClient = apnsClientDev;

            final Future<PushNotificationResponse<SimpleApnsPushNotification>> future = apnsClient.sendNotification(pushNotification);

            future.addListener(new GenericFutureListener<Future<PushNotificationResponse>>() {
                @Override
                public void operationComplete(Future<PushNotificationResponse> pushNotificationResponseFuture) throws Exception {
                    if (future.isSuccess()) {
                        final PushNotificationResponse<SimpleApnsPushNotification> response = future.getNow();
                        if (response.isAccepted()) {
                            successCnt.incrementAndGet();
                        } else {
                            Date invalidTime = response.getTokenInvalidationTimestamp();
                            LogHelper.i("Notification rejected by the APNs gateway: " + response.getRejectionReason());
                            if (invalidTime != null) {
                                LogHelper.i("\t…and the token is invalid as of " + response.getTokenInvalidationTimestamp());
                            }
                        }
                    } else {
                        LogHelper.i("send notification device token="+token+" is failed "+ future.cause().getMessage());
                    }
                    latch.countDown();
                    semaphore.release();
                }
            });
        }

        try {
            latch.await(20, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            LogHelper.i("ios push latch await failed!");
            e.printStackTrace();
        }

        LogHelper.i("test pushMessage success. [共推送" + total + "个][成功" + (successCnt.get()) + "个]");
    }

    public void push(final String deviceTokens, String alertTitle, String alertBody,Map cutom,boolean isProd) {
        List tokens = new ArrayList();
        tokens.add(deviceTokens);
        push(tokens,alertTitle,alertBody,cutom,isProd);
    }
}
